Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
82 KB
Referenced Files
None
Subscribers
None
diff --git a/util/network/hawknl/src/sock.cpp b/util/network/hawknl/src/sock.cpp
index 88a5f760..6fbd782f 100644
--- a/util/network/hawknl/src/sock.cpp
+++ b/util/network/hawknl/src/sock.cpp
@@ -1,2779 +1,2783 @@
/*
HawkNL cross platform network library
Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
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 Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifndef FD_SETSIZE
#define FD_SETSIZE 8192
#endif
#if !defined(PS3) && !defined(WII)
#include <memory.h>
#endif
#include <stdio.h>
#include <string.h>
#if defined (_WIN32_WCE)
#define EAGAIN 11
#define errno GetLastError()
#else
#include <errno.h>
#endif
#if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
#include "hawknl/wsock.h"
#elif defined Macintosh
#include <Types.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/time.h>
#include <LowMem.h>
#define closesocket close
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SOCKET int
#define sockerrno errno
/* define INADDR_NONE if not already */
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long) -1)
#endif
#else
/* Unix-style systems */
#ifdef SOLARIS
#include <sys/filio.h> /* for FIONBIO */
#endif
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#ifndef WII
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef PS3
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#else
#include <net/select.h>
#endif
#include <arpa/inet.h>
#ifdef PS3
#include <net/netdb.h>
#else
#include <netdb.h>
#endif
#else
#include <network.h>
/* FIXME: BAAARFFFF at least move these things to a different header */
#define send net_send
#define sendto net_sendto
#define gethostbyname net_gethostbyname
#define recv net_recv
#define recvfrom net_recvfrom
#define bind net_bind
#define listen net_listen
#define socket net_socket
#define connect net_connect
#define accept net_accept
#define shutdown net_shutdown
#define select net_select
#define setsockopt net_setsockopt
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen){
return -1;
}
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type){
return NULL;
}
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen){
return -1;
}
#endif
#define closesocket close
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SOCKET int
#define SD_RECEIVE 0
#define SD_SEND 1
#define SD_BOTH 2
#define sockerrno errno
/* define INADDR_NONE if not already */
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long) -1)
#endif
/* SGI and MacOS X do not include socklen_t */
// #if defined __sgi || defined MACOSX
#if defined __sgi
typedef int socklen_t;
#endif
#endif /* HL_WINDOWS_APP*/
/* Uncomment if multicast should be used */
// #define WANT_MULTICAST
#include "hawknl/nlinternal.h"
#include "hawknl/group.h"
#include "hawknl/sock.h"
#include "util/funcs.h"
#ifndef IN_MULTICAST
#define IN_MULTICAST(i) (((unsigned long)(i) & 0xF0000000) == (unsigned long)0xE0000000)
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN NL_MAX_STRING_LENGTH
#endif
#define NL_CONNECT_STRING "HawkNL request connection."
#define NL_REPLY_STRING "HawkNL connection OK."
#define NL_HEADER_LEN 4
/*
* Portable NLMAX() function macro
*/
#define NLMAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
#define NLMIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
static volatile NLuint ouraddress, bindaddress;
#if defined(PS3) || defined(WII)
int backlog = 10;
#else
int backlog = SOMAXCONN;
#endif
static volatile int multicastTTL = 1;
NLboolean reuseaddress = NL_FALSE;
static volatile NLboolean nlTCPNoDelay = NL_FALSE;
static NLaddress *alladdr = NULL;
typedef struct
{
NLaddress /*@temp@*/*address;
NLchar /*@temp@*/*name;
NLsocket socket;
} NLaddress_ex_t;
extern SOCKET nlGroupGetFdset(NLint group, /*@out@*/ fd_set *fd);
extern NLushort ipx_GetPort(SOCKET socket);
extern NLushort ipx_GetPortFromAddr(const NLaddress *address);
/*
This is a Winsock work around to be able to bind() to more than 3976 ports
*/
#ifdef HL_WINDOWS_APP
/* In memory of my step-father, Don Portlock,
* who passed away Jan 12, 2001 - Phil
*/
static Util::Thread::Lock portlock;
static volatile NLushort nextport = 1024;
static NLushort sock_getNextPort(void)
{
NLlong temp;
Util::Thread::acquireLock(&portlock);
temp = (NLlong)nextport;
if(++temp > 65535)
{
/* skip the well known ports */
temp = 1024;
}
nextport = (NLushort)temp;
Util::Thread::releaseLock(&portlock);
return nextport;
}
static NLint sock_bind(SOCKET socket, const struct sockaddr *a, int len)
{
struct sockaddr_in *addr = (struct sockaddr_in *)a;
int ntries = 500; /* this is to prevent an infinite loop */
NLboolean found = NL_FALSE;
/* check to see if the port is already specified */
if(addr->sin_port != 0)
{
/* do the normal bind */
return bind(socket, a, len);
}
/* let's find our own port number */
while(ntries-- > 0)
{
addr->sin_port = htons(sock_getNextPort());
if(bind(socket, (struct sockaddr *)addr, len) != SOCKET_ERROR)
{
found = NL_TRUE;
break;
}
}
if(found == NL_TRUE)
{
return 0;
}
/* could not find a port, restore the port number back to 0 */
addr->sin_port = 0;
/* return error */
return SOCKET_ERROR;
}
static int sock_connect(SOCKET socket, const struct sockaddr* a, int len )
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
if(sock_bind(socket, (struct sockaddr *)&addr, (int)sizeof(addr)) == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
return connect(socket, a, len);
}
void nlFD_CLR(SOCKET fd, fd_set *set)
{
u_int i;
for(i=0;i<set->fd_count;i++)
{
if(set->fd_array[i] == fd)
{
while(i < set->fd_count-1)
{
set->fd_array[i] = set->fd_array[i+1];
i++;
}
set->fd_count--;
break;
}
}
}
void nlFD_SET(SOCKET fd, /*@out@*/ fd_set *set)
{
if(set->fd_count < FD_SETSIZE)
set->fd_array[set->fd_count++]=fd;
}
/* This function is inlined for speed over the Winsock function */
int nlWSAFDIsSet(SOCKET fd, fd_set *set)
{
int i = (int)set->fd_count;
while(i-- != 0)
{
if (set->fd_array[i] == fd)
return 1;
}
return 0;
}
#else
#define sock_bind bind
#define sock_connect connect
#endif /* HL_WINDOWS_APP */
/*
helper functions for NL_RELIABLE_PACKETS
*/
static NLint rpGroup; /* the group to hold all the NL_RELIABLE_PACKETS sockets */
static Util::Thread::Lock rpMutex; /* mutex to lock the functions */
static NLboolean needThread = NL_TRUE; /* do we need to spawn a thread? */
static NLint rpSocketCount = 0; /* total count of NL_RELIABLE_PACKETS sockets */
static volatile NLint rpBufferedCount = 0;/* count of sockets that are buffering data */
static void sock_WritePacketCheckPending(NLsocket socket)
{
nl_socket_t *sock = nlSockets[socket];
/* first check for data waiting to be sent */
if(sock->sendlen > 0)
{
NLint count, size = NL_MAX_PACKET_LENGTH + NL_HEADER_LEN;
if(size > sock->sendlen)
{
size = sock->sendlen;
}
count = send((SOCKET)sock->realsocket, (char *)sock->outbuf, size, 0);
if(count > 0)
{
sock->sendlen -= count;
if(sock->sendlen > 0)
{
/* move remaining data to beginning of outbuf */
memmove(sock->outbuf, (sock->outbuf + count), (size_t)sock->sendlen);
}
else
{
rpBufferedCount--;
}
}
}
}
static void *sock_rpThread(void *p)
{
static NLsocket *sockets = NULL;
static NLint maxsockets = 0;
/* allocate memory */
if(sockets == NULL)
{
sockets = (NLsocket *)malloc(sizeof(NLsocket *) * 16);
if(sockets == NULL)
{
needThread = NL_TRUE;
return NULL;
}
maxsockets = 16;
}
while(rpGroup != NL_INVALID)
{
NLint count = maxsockets;
/* make sure there is something to do */
if(rpSocketCount == 0 || rpBufferedCount == 0)
{
goto loopend;
}
/* see if we need to allocate more memory */
if(maxsockets < rpSocketCount)
{
NLsocket *temp;
while(maxsockets < rpSocketCount)
{
maxsockets *= 2;
}
temp = (NLsocket *)realloc((void *)sockets, sizeof(NLsocket *) * maxsockets);
if(temp == NULL)
{
goto cleanup;
}
sockets = temp;
}
/* we can now get the sockets */
if(nlGroupGetSockets(rpGroup, sockets, &count) == NL_FALSE)
{
goto cleanup;
}
while(count-- > 0 && rpBufferedCount > 0)
{
NLsocket socket = sockets[count];
(void)nlLockSocket(socket, NL_WRITE);
sock_WritePacketCheckPending(socket);
nlUnlockSocket(socket, NL_WRITE);
}
loopend:
Util::rest(50);
}
cleanup:
free(sockets);
sockets = NULL;
maxsockets = 0;
needThread = NL_TRUE;
return p;
}
static void sock_AddSocket(NLsocket socket)
{
Util::Thread::acquireLock(&rpMutex);
(void)nlGroupAddSocket(rpGroup, socket);
rpSocketCount++;
if(needThread == NL_TRUE){
Util::Thread::Id thread;
/* the thread was initially made in a detached state which
* is why the thread is it not stored -- because it wasn't
* ever joined later on.
*/
Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) sock_rpThread, NULL);
needThread = NL_FALSE;
}
Util::Thread::releaseLock(&rpMutex);
}
static void sock_DeleteSocket(NLsocket socket)
{
Util::Thread::acquireLock(&rpMutex);
(void)nlGroupDeleteSocket(rpGroup, socket);
rpSocketCount--;
Util::Thread::releaseLock(&rpMutex);
}
/*
handle some common connection errors so the app knows when a connection has been dropped
*/
NLint sock_Error(void)
{
switch (sockerrno) {
#ifdef HL_WINDOWS_APP
case WSABASEERR:
return 0;
#endif
case EWOULDBLOCK:
return 0;
case ENETRESET:
case EHOSTUNREACH:
case ECONNABORTED:
case ECONNRESET:
case ENETUNREACH:
case ETIMEDOUT:
nlSetError(NL_SOCK_DISCONNECT);
break;
default:
nlSetError(NL_SYSTEM_ERROR);
break;
}
return NL_INVALID;
}
NLboolean sock_SetBlocking(SOCKET socket, NLboolean arg)
{
int rc;
unsigned long i = 1;
if(arg == NL_TRUE){
i = 0;
}
#if defined(PS3) || defined(WII)
/* FIXME: set sockets to blocking or not */
return NL_TRUE;
#else
rc = ioctl(socket, FIONBIO, &i);
if(rc == SOCKET_ERROR){
return NL_FALSE;
}
return NL_TRUE;
#endif
}
NLboolean sock_SetBroadcast(SOCKET socket)
{
int i = 1;
if(setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
return NL_TRUE;
}
NLboolean sock_SetReuseAddr(nl_socket_t *sock)
{
int i = 1;
if(setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
sock->reuseaddr = NL_TRUE;
return NL_TRUE;
}
static NLboolean sock_SetTCPNoDelay(nl_socket_t *sock, NLboolean arg)
{
NLenum type = sock->type;
SOCKET realsocket = (SOCKET)sock->realsocket;
int i;
if(type == NL_TCP || type == NL_TCP_PACKETS)
{
arg = (NLboolean)(arg != (NLboolean)0 ? NL_TRUE : NL_FALSE);
i = (int)arg;
#ifdef PS3
/* FIXME: maybe use SO_SNDTIMEO? */
#else
if(setsockopt(realsocket, IPPROTO_TCP, TCP_NODELAY, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
#endif
}
sock->TCPNoDelay = arg;
return NL_TRUE;
}
static NLboolean sock_SetMulticastTTL(nl_socket_t *sock, NLint ttl)
{
SOCKET realsocket = (SOCKET)sock->realsocket;
unsigned char cttl;
/* make sure we have a valid TTL */
if(ttl > 255) ttl = 255;
if(ttl < 1) ttl = 1;
cttl = (unsigned char)ttl;
#ifdef WANT_MULTICAST
/* first try setsockopt by passing a 'char', the Unix standard */
if(setsockopt(realsocket, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&cttl, (int)sizeof(cttl)) == SOCKET_ERROR)
{
/* if that failed, we might be on a Windows system
that requires an 'int' */
if(setsockopt(realsocket, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&ttl, (int)sizeof(ttl)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
}
sock->TTL = ttl;
return NL_TRUE;
#else
return NL_FALSE;
#endif
}
static NLsocket sock_SetSocketOptions(NLsocket s)
{
nl_socket_t *sock = nlSockets[s];
NLenum type = sock->type;
SOCKET realsocket = (SOCKET)sock->realsocket;
if(type == NL_RELIABLE || type == NL_RELIABLE_PACKETS)
{
sock->reliable = NL_TRUE;
if(type == NL_RELIABLE_PACKETS)
{
sock->packetsync = NL_TRUE;
}
}
else
{
sock->reliable = NL_FALSE;
}
if(sock->driver == NL_IP)
{
if(sock_SetTCPNoDelay(sock, sock->TCPNoDelay) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_INVALID;
}
}
if(reuseaddress == NL_TRUE)
{
if(sock_SetReuseAddr(sock) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_INVALID;
}
}
if(sock_SetBlocking(realsocket, sock->blocking) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_INVALID;
}
return s;
}
#if defined(PS3) || defined(WII)
static int gethostname(char * name, size_t length){
snprintf(name, length, "host");
}
#endif
static NLuint sock_GetHostAddress(void)
{
struct hostent *local;
char buff[MAXHOSTNAMELEN];
if(gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR){
return INADDR_NONE;
}
buff[MAXHOSTNAMELEN - 1] = '\0';
local = gethostbyname(buff);
if(!local)
return (NLuint)htonl(0x7f000001);
return *(NLuint *)local->h_addr_list[0];
}
static NLushort sock_GetPort(SOCKET socket)
{
struct sockaddr_in addr;
socklen_t len;
len = (socklen_t)sizeof(struct sockaddr_in);
if(getsockname(socket, (struct sockaddr *) &addr, &len) == SOCKET_ERROR)
{
return 0;
}
return ntohs(addr.sin_port);
}
NLboolean sock_Init(void)
{
#ifdef HL_WINDOWS_APP
WSADATA libmibWSAdata;
/* We must have Winsock 2.0 */
if(WSAStartup(MAKEWORD(2, 0),&libmibWSAdata) != 0)
{
return NL_FALSE;
}
if(Util::Thread::initializeLock(&portlock) != true)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
#endif
if(Util::Thread::initializeLock(&rpMutex) != true)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
if((rpGroup = nlGroupCreate()) == NL_INVALID)
{
return NL_FALSE;
}
ouraddress = sock_GetHostAddress();
if(ouraddress == (NLuint)INADDR_NONE)
{
return NL_FALSE;
}
bindaddress = INADDR_ANY;
return NL_TRUE;
}
void sock_Shutdown(void)
{
#ifdef HL_WINDOWS_APP
(void)WSACleanup();
Util::Thread::destroyLock(&portlock);
Util::Thread::destroyLock(&rpMutex);
(void)nlGroupDestroy(rpGroup);
rpGroup = NL_INVALID;
#endif
if(alladdr != NULL)
{
free(alladdr);
alladdr = NULL;
}
}
NLboolean sock_Listen(NLsocket socket)
{
nl_socket_t *sock = nlSockets[socket];
if(sock->listen == NL_TRUE)
{
return NL_TRUE;
}
if(sock->reliable == NL_TRUE) /* TCP */
{
/* check for unbound socket */
if(sock->localport == 0)
{
NLint result;
/* bind socket */
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
((struct sockaddr_ipx *)&sock->addressin)->sa_family = AF_IPX;
memset(((struct sockaddr_ipx *)&sock->addressin)->sa_netnum, 0, 4);
memset(((struct sockaddr_ipx *)&sock->addressin)->sa_nodenum, 0, 6);
((struct sockaddr_ipx *)&sock->addressin)->sa_socket = 0;
result = bind((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
(int)sizeof(struct sockaddr_ipx));
}
else
#endif
{
((struct sockaddr_in *)&sock->addressin)->sin_family = AF_INET;
((struct sockaddr_in *)&sock->addressin)->sin_addr.s_addr = bindaddress;
((struct sockaddr_in *)&sock->addressin)->sin_port = 0;
result = sock_bind((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
(int)sizeof(struct sockaddr_in));
}
if(result == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
}
if(listen((SOCKET)sock->realsocket, backlog) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
}
sock->listen = NL_TRUE;
return NL_TRUE;
}
static SOCKET sock_AcceptUDP(NLsocket nlsocket, /*@out@*/struct sockaddr_in *newaddr)
{
nl_socket_t *sock = nlSockets[nlsocket];
struct sockaddr_in ouraddr;
SOCKET newsocket;
NLushort localport;
NLbyte buffer[NL_MAX_STRING_LENGTH];
socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
NLint slen = (NLint)sizeof(NL_CONNECT_STRING);
NLbyte reply = (NLbyte)0x00;
NLint count = 0;
/* Get the packet and remote host address */
if(recvfrom((SOCKET)sock->realsocket, buffer, (int)sizeof(buffer), 0,
(struct sockaddr *)newaddr, &len) < (int)sizeof(NL_CONNECT_STRING))
{
nlSetError(NL_NO_PENDING);
return INVALID_SOCKET;
}
/* Let's check for the connection string */
buffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
if(strcmp(buffer, NL_CONNECT_STRING) != 0)
{
nlSetError(NL_NO_PENDING);
return INVALID_SOCKET;
}
/* open up a new socket on this end */
newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(newsocket == INVALID_SOCKET)
{
nlSetError(NL_SYSTEM_ERROR);
(void)closesocket(newsocket);
return INVALID_SOCKET;
}
ouraddr.sin_family = AF_INET;
ouraddr.sin_addr.s_addr = bindaddress;
/* system assigned port number */
ouraddr.sin_port = 0;
if(sock_bind(newsocket, (struct sockaddr *)&ouraddr, len) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
(void)closesocket(newsocket);
return INVALID_SOCKET;
}
/* get the new port */
localport = sock_GetPort(newsocket);
/* create the return message */
writeShort(buffer, count, localport);
writeString(buffer, count, (NLchar *)TEXT(NL_REPLY_STRING));
/* send back the reply with our new port */
if(sendto((SOCKET)sock->realsocket, buffer, count, 0, (struct sockaddr *)newaddr,
(int)sizeof(struct sockaddr_in)) < count)
{
nlSetError(NL_SYSTEM_ERROR);
(void)closesocket(newsocket);
return INVALID_SOCKET;
}
/* send back a 0 length packet from our new port, needed for firewalls */
if(sendto(newsocket, &reply, 0, 0,
(struct sockaddr *)newaddr,
(int)sizeof(struct sockaddr_in)) < 0)
{
nlSetError(NL_SYSTEM_ERROR);
(void)closesocket(newsocket);
return INVALID_SOCKET;
}
/* connect the socket */
if(connect(newsocket, (struct sockaddr *)newaddr,
(int)sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
(void)closesocket(newsocket);
return INVALID_SOCKET;
}
return newsocket;
}
NLsocket sock_AcceptConnection(NLsocket socket)
{
nl_socket_t *sock = nlSockets[socket];
nl_socket_t *newsock = NULL;
NLsocket newsocket = NL_INVALID;
SOCKET realsocket = INVALID_SOCKET;
struct sockaddr_in newaddr;
socklen_t len = (socklen_t)sizeof(newaddr);
memset(&newaddr, 0, sizeof(newaddr));
if(sock->listen != NL_TRUE)
{
nlSetError(NL_NOT_LISTEN);
return NL_INVALID;
}
if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) /* TCP */
{
SOCKET s = 101;
/* !@#$% metrowerks compiler, try to get it to actually produce some code */
s = accept((SOCKET)(sock->realsocket), (struct sockaddr *)&newaddr, &len);
realsocket = s;
if(realsocket == INVALID_SOCKET)
{
if(sockerrno == (int)EWOULDBLOCK || errno == EAGAIN)/* yes, we need to use errno here */
{
nlSetError(NL_NO_PENDING);
}
else
{
nlSetError(NL_SYSTEM_ERROR);
}
return NL_INVALID;
}
}
else if(sock->type == NL_UNRELIABLE)/* UDP*/
{
realsocket = sock_AcceptUDP(socket, &newaddr);
if(realsocket == INVALID_SOCKET)
{
/* error is already set in sock_AcceptUDP */
return NL_INVALID;
}
}
else /* broadcast or multicast */
{
nlSetError(NL_WRONG_TYPE);
return NL_INVALID;
}
newsocket = nlGetNewSocket();
if(newsocket == NL_INVALID)
{
return NL_INVALID;
}
if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
{
return NL_INVALID;
}
newsock = nlSockets[newsocket];
/* update the remote address */
memcpy((char *)&newsock->addressin, (char *)&newaddr, sizeof(struct sockaddr_in));
newsock->realsocket = (NLint)realsocket;
newsock->localport = sock_GetPort(realsocket);
newsock->remoteport = sock_GetPortFromAddr((NLaddress *)&newsock->addressin);
newsock->type = sock->type;
newsock->TCPNoDelay = sock->TCPNoDelay;
newsock->connected = NL_TRUE;
newsock->blocking = sock->blocking;
if(newsock->type == NL_RELIABLE_PACKETS)
{
sock_AddSocket(newsocket);
}
return sock_SetSocketOptions(newsocket);
}
NLsocket sock_OpenINT(NLushort port, NLenum type, NLenum driver)
{
nl_socket_t *newsock;
NLsocket newsocket;
SOCKET realsocket;
switch (type) {
case NL_RELIABLE: /* TCP/SPX */
case NL_RELIABLE_PACKETS:
#ifdef NL_INCLUDE_IPX
if(driver == NL_IPX)
{
realsocket = socket(PF_IPX, SOCK_SEQPACKET, NSPROTO_SPXII);
type = NL_RELIABLE;
}
else
#endif
{
realsocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
}
break;
case NL_UNRELIABLE: /* UDP/IPX */
case NL_BROADCAST: /* UDP/IPX broadcast */
case NL_UDP_MULTICAST: /* UDP multicast */
#ifdef NL_INCLUDE_IPX
if(driver == NL_IPX)
{
if(type == NL_UDP_MULTICAST)
{
nlSetError(NL_INVALID_ENUM);
return NL_INVALID;
}
realsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
}
else
#endif
{
realsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
break;
default:
nlSetError(NL_INVALID_ENUM);
return NL_INVALID;
}
if(realsocket == INVALID_SOCKET)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_INVALID;
}
newsocket = nlGetNewSocket();
if(newsocket == NL_INVALID)
{
return NL_INVALID;
}
if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
{
return NL_INVALID;
}
newsock = nlSockets[newsocket];
newsock->realsocket = (NLint)realsocket;
newsock->type = type;
newsock->TCPNoDelay = nlTCPNoDelay;
if(sock_SetSocketOptions(newsocket) == NL_INVALID)
{
nlUnlockSocket(newsocket, NL_BOTH);
(void)sock_Close(newsocket);
return NL_INVALID;
}
/* do not bind a TCP/SPX socket here if the port is 0; let connect assign the port */
if((type == NL_RELIABLE || type == NL_RELIABLE_PACKETS) && port == 0)
{
newsock->localport = 0;
}
else
{
NLint result;
#ifdef NL_INCLUDE_IPX
if(driver == NL_IPX)
{
((struct sockaddr_ipx *)&newsock->addressin)->sa_family = AF_IPX;
memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_netnum, 0, 4);
memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_nodenum, 0, 6);
((struct sockaddr_ipx *)&newsock->addressin)->sa_socket = htons((unsigned short)port);
result = bind((SOCKET)realsocket, (struct sockaddr *)&newsock->addressin,
(int)sizeof(struct sockaddr_ipx));
}
else
#endif
{
((struct sockaddr_in *)&newsock->addressin)->sin_family = AF_INET;
((struct sockaddr_in *)&newsock->addressin)->sin_addr.s_addr = bindaddress;
((struct sockaddr_in *)&newsock->addressin)->sin_port = htons((unsigned short)port);
result = sock_bind(realsocket, (struct sockaddr *)&newsock->addressin,
(int)sizeof(struct sockaddr_in));
}
if(result == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
nlUnlockSocket(newsocket, NL_BOTH);
(void)sock_Close(newsocket);
return NL_INVALID;
}
if(type == NL_BROADCAST)
{
if(sock_SetBroadcast(realsocket) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
nlUnlockSocket(newsocket, NL_BOTH);
(void)sock_Close(newsocket);
return NL_INVALID;
}
#ifdef NL_INCLUDE_IPX
if(driver == NL_IPX)
{
((struct sockaddr_ipx *)&newsock->addressout)->sa_family = AF_IPX;
memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_netnum, 0, 4);
memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_nodenum, 0xff, 6);
((struct sockaddr_ipx *)&newsock->addressout)->sa_socket = htons((unsigned short)port);
}
else
#endif
{
((struct sockaddr_in *)&newsock->addressout)->sin_family = AF_INET;
((struct sockaddr_in *)&newsock->addressout)->sin_addr.s_addr = INADDR_BROADCAST;
((struct sockaddr_in *)&newsock->addressout)->sin_port = htons((unsigned short)port);
}
}
#ifdef NL_INCLUDE_IPX
if(driver == NL_IPX)
{
newsock->localport = ipx_GetPort(realsocket);
}
else
#endif
{
newsock->localport = sock_GetPort(realsocket);
}
}
if(type == NL_RELIABLE_PACKETS)
{
sock_AddSocket(newsocket);
}
newsock->driver = driver;
nlUnlockSocket(newsocket, NL_BOTH);
return newsocket;
}
NLsocket sock_Open(NLushort port, NLenum type)
{
return sock_OpenINT(port, type, NL_IP);
}
static NLboolean sock_ConnectUDP(NLsocket socket, const NLaddress *address)
{
nl_socket_t *sock = nlSockets[socket];
time_t begin, t;
socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
sock->conerror = NL_FALSE;
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
len = (socklen_t)sizeof(struct sockaddr_ipx);
}
#endif
if(sendto((SOCKET)sock->realsocket, (char *)NL_CONNECT_STRING, (NLint)sizeof(NL_CONNECT_STRING),
0, (struct sockaddr *)address, len)
== SOCKET_ERROR)
{
if(sock->blocking == NL_TRUE)
{
nlSetError(NL_SYSTEM_ERROR);
}
else
{
sock->conerror = NL_TRUE;
}
return NL_FALSE;
}
(void)time(&begin);
+
+ /* FIXME! If the udp server is not open then recvfrom will hang forever. Use
+ * select or something here to truly test if 6 seconds is up.
+ */
/* try for six seconds */
while((time(&t) - begin) < 6)
{
NLbyte buffer[NL_MAX_STRING_LENGTH];
NLbyte *pbuffer = buffer;
NLushort newport;
NLint slen = (NLint)(sizeof(NL_REPLY_STRING) + sizeof(newport));
NLint received;
NLbyte reply = (NLbyte)0;
received = recvfrom((SOCKET)sock->realsocket, (char *)buffer, (int)sizeof(buffer), 0,
(struct sockaddr *)&sock->addressin, &len);
if(received == SOCKET_ERROR)
{
if(sockerrno != (int)EWOULDBLOCK)
{
if(sock->blocking == NL_TRUE)
{
nlSetError(NL_CON_REFUSED);
}
else
{
sock->conerror = NL_TRUE;
}
return NL_FALSE;
}
}
if(received >= slen)
{
NLint count = 0;
/* retrieve the port number */
readShort(buffer, count, newport);
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
((struct sockaddr_ipx *)&sock->addressin)->sa_socket = htons(newport);
}
else
#endif
{
((struct sockaddr_in *)&sock->addressin)->sin_port = htons(newport);
}
/* Lets check for the reply string */
pbuffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
pbuffer += sizeof(newport);
if(strcmp(pbuffer, NL_REPLY_STRING) == 0)
{
if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
== SOCKET_ERROR)
{
if(sock->blocking == NL_TRUE)
{
nlSetError(NL_SYSTEM_ERROR);
}
else
{
sock->conerror = NL_TRUE;
}
return NL_FALSE;
}
/* send back a 0 length packet to the new port, needed for firewalls */
if(send((SOCKET)sock->realsocket, &reply, 0, 0) == SOCKET_ERROR)
{
if(sock->blocking == NL_TRUE)
{
nlSetError(NL_SYSTEM_ERROR);
}
else
{
sock->conerror = NL_TRUE;
}
return NL_FALSE;
}
/* success! */
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
}
else
#endif
{
sock->localport = sock_GetPort((SOCKET)sock->realsocket);
sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressin);
}
sock->connected = NL_TRUE;
sock->connecting = NL_FALSE;
return NL_TRUE;
}
}
Util::rest(NL_CONNECT_SLEEP);
}
if(sock->blocking == NL_TRUE)
{
nlSetError(NL_CON_REFUSED);
}
else
{
sock->conerror = NL_TRUE;
}
sock->connecting = NL_FALSE;
return NL_FALSE;
}
static void *sock_ConnectUDPAsynchInt(void /*@owned@*/*addr)
{
NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
(void)sock_ConnectUDP(address->socket, address->address);
free(addr);
return NULL;
}
static NLboolean sock_ConnectUDPAsynch(NLsocket socket, const NLaddress *address)
{
NLaddress_ex_t /*@dependent@*/*addr;
nl_socket_t *sock = nlSockets[socket];
addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
if(addr == NULL)
{
nlSetError(NL_OUT_OF_MEMORY);
return NL_FALSE;
}
addr->address = (NLaddress *)address;
addr->socket = socket;
sock->connecting = NL_TRUE;
sock->conerror = NL_FALSE;
Util::Thread::Id thread;
if (!Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) sock_ConnectUDPAsynchInt, (void *)addr)){
return NL_FALSE;
}
return NL_TRUE;
}
static NLboolean sock_ConnectMulticast(NLsocket socket, const NLaddress *address)
{
#ifdef WANT_MULTICAST
struct ip_mreq mreq;
nl_socket_t *sock = nlSockets[socket];
if(sock->reliable == NL_TRUE)
{
nlSetError(NL_WRONG_TYPE);
return NL_FALSE;
}
if(!IN_MULTICAST(ntohl(((struct sockaddr_in *)address)->sin_addr.s_addr)))
{
nlSetError(NL_BAD_ADDR);
return NL_FALSE;
}
memcpy((char *)&sock->addressin, (char *)address, sizeof(NLaddress));
memcpy((char *)&sock->addressout, (char *)address, sizeof(NLaddress));
/* join the multicast group */
mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)address)->sin_addr.s_addr;
mreq.imr_interface.s_addr = bindaddress;
if(setsockopt((SOCKET)sock->realsocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&mreq, (int)sizeof(mreq)) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
sock->localport = sock_GetPort((SOCKET)sock->realsocket);
sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressout);
return sock_SetMulticastTTL(sock, multicastTTL);
#else
return NL_FALSE;
#endif
}
NLboolean sock_Connect(NLsocket socket, const NLaddress *address)
{
nl_socket_t *sock = nlSockets[socket];
memcpy((char *)&sock->addressin, (char *)address, sizeof(NLaddress));
if(sock->connected == NL_TRUE)
{
nlSetError(NL_CONNECTED);
return NL_FALSE;
}
if(sock->connecting == NL_TRUE)
{
nlSetError(NL_CON_PENDING);
return NL_FALSE;
}
if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
{
socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
len = (socklen_t)sizeof(struct sockaddr_ipx);
if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
== SOCKET_ERROR)
{
if(sock->blocking == NL_FALSE &&
(sockerrno == (int)EWOULDBLOCK || sockerrno == (int)EINPROGRESS))
{
sock->connecting = NL_TRUE;
}
else
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
}
sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
}
else
#endif
{
if(sock_connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
== SOCKET_ERROR)
{
if(sock->blocking == NL_FALSE &&
(sockerrno == (int)EWOULDBLOCK || sockerrno == (int)EINPROGRESS))
{
sock->connecting = NL_TRUE;
}
else
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
}
sock->localport = sock_GetPort((SOCKET)sock->realsocket);
sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressin);
}
if(sock->connecting == NL_FALSE)
{
sock->connected = NL_TRUE;
}
return NL_TRUE;
}
else if(sock->type == NL_UDP_MULTICAST)
{
return sock_ConnectMulticast(socket, &sock->addressin);
}
else if(sock->type == NL_UNRELIABLE)
{
if(sock->blocking == NL_TRUE)
{
return sock_ConnectUDP(socket, &sock->addressin);
}
else
{
return sock_ConnectUDPAsynch(socket, &sock->addressin);
}
}
else
{
nlSetError(NL_WRONG_TYPE);
}
return NL_FALSE;
}
void sock_Close(NLsocket socket)
{
nl_socket_t *sock = nlSockets[socket];
if(sock->type == NL_UDP_MULTICAST)
{
#ifdef WANT_MULTICAST
struct ip_mreq mreq;
/* leave the multicast group */
mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)&sock->addressout)->sin_addr.s_addr;
mreq.imr_interface.s_addr = bindaddress;
(void)setsockopt((SOCKET)sock->realsocket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
(char *)&mreq, (int)sizeof(mreq));
#endif
}
if(sock->type == NL_RELIABLE_PACKETS)
{
/* check for unsent data */
if(sock->sendlen > 0)
{
int tries = 200;
/* 200 * 50 ms = up to a 10 second delay to allow data to be sent */
while(tries-- > 0 && sock->sendlen > 0)
{
Util::rest(50);
}
}
sock_DeleteSocket(socket);
}
if((sock->type == NL_RELIABLE_PACKETS || sock->type == NL_RELIABLE) && sock->listen == NL_FALSE)
{
struct linger l = {1, 1};
(void)setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_LINGER, (const char *)&l, (int)sizeof(l));
(void)shutdown((SOCKET)sock->realsocket, SD_RECEIVE);
}
else
{
(void)shutdown((SOCKET)sock->realsocket, SD_BOTH);
}
(void)closesocket((SOCKET)sock->realsocket);
}
/* internal function to read reliable packets from TCP stream */
static NLint sock_ReadPacket(NLsocket socket, NLvoid /*@out@*/ *buffer, NLint nbytes,
NLboolean checkonly)
{
nl_socket_t *sock = nlSockets[socket];
/* skip error reporting if checkonly is TRUE */
/* check for sync */
if(sock->packetsync == NL_FALSE)
{
if(checkonly == NL_FALSE)
{
nlSetError(NL_PACKET_SYNC);
}
else
{
sock->readable = NL_TRUE;
}
return NL_INVALID;
}
if(sock->message_end == NL_TRUE && checkonly == NL_FALSE && sock->reclen == 0)
{
sock->message_end = NL_FALSE;
nlSetError(NL_MESSAGE_END);
return NL_INVALID;
}
/* allocate some temp storage the first time through */
if(sock->inbuf == NULL)
{
sock->inbuflen = (nbytes + nbytes / 4 + NL_HEADER_LEN);
if(sock->inbuflen < 1024)
{
sock->inbuflen = 1024;
}
else if(sock->inbuflen > NL_MAX_PACKET_LENGTH + NL_MAX_PACKET_LENGTH/4)
{
sock->inbuflen = NL_MAX_PACKET_LENGTH + NL_MAX_PACKET_LENGTH/4;
}
sock->inbuf = (NLbyte *)malloc((size_t)sock->inbuflen);
if(sock->inbuf == NULL)
{
if(checkonly == NL_FALSE)
{
sock->inbuflen = 0;
nlSetError(NL_OUT_OF_MEMORY);
}
return NL_INVALID;
}
}
/* if inbuf is empty, get some data */
if(sock->reclen < NL_HEADER_LEN)
{
NLint count;
count = recv((SOCKET)sock->realsocket, (char *)(sock->inbuf + sock->reclen), (sock->inbuflen - sock->reclen), 0);
if(count == SOCKET_ERROR)
{
if(checkonly == NL_FALSE)
{
return sock_Error();
}
else
{
sock->readable = NL_TRUE;
return NL_INVALID;
}
}
if(count == 0)
{
if(checkonly == NL_FALSE)
{
nlSetError(NL_MESSAGE_END);
}
else
{
sock->message_end = NL_TRUE;
sock->readable = NL_TRUE;
}
return NL_INVALID;
}
sock->reclen += count;
}
/* start parsing the packet */
if(sock->reclen >= NL_HEADER_LEN)
{
NLboolean done = NL_FALSE;
NLushort len;
NLint c = 2;
/* check for valid packet */
if(sock->inbuf[0] != 'N' || sock->inbuf[1] != 'L')
{
/* packet is not valid, we are somehow out of sync,
or we are talking to a regular TCP stream */
if(checkonly == NL_FALSE)
{
nlSetError(NL_PACKET_SYNC);
}
else
{
sock->readable = NL_TRUE;
}
sock->packetsync = NL_FALSE;
return NL_INVALID;
}
/* read the length of the packet */
readShort(sock->inbuf, c, len);
if(len > NL_MAX_PACKET_LENGTH)
{
/* packet is not valid, or we are talking to a regular TCP stream */
if(checkonly == NL_FALSE)
{
nlSetError(NL_PACKET_SYNC);
}
else
{
sock->readable = NL_TRUE;
}
sock->packetsync = NL_FALSE;
return NL_INVALID;
}
/* check to see if we need to make the inbuf storage larger */
if((NLint)len > sock->inbuflen)
{
NLint newbuflen;
NLbyte *temp;
newbuflen = (len + len / 4 + NL_HEADER_LEN);
temp = (NLbyte *)realloc(sock->inbuf, (size_t)newbuflen);
if(temp == NULL)
{
if(checkonly == NL_FALSE)
{
nlSetError(NL_OUT_OF_MEMORY);
}
return NL_INVALID;
}
sock->inbuf = temp;
sock->inbuflen = newbuflen;
}
if(checkonly == NL_FALSE)
{
if(len > (NLushort)nbytes)
{
nlSetError(NL_BUFFER_SIZE);
return NL_INVALID;
}
}
/* see if we need to get more of the packet */
if(len > (NLushort)(sock->reclen - c))
{
done = NL_FALSE;
while(done == NL_FALSE)
{
NLint count;
if(checkonly == NL_FALSE)
{
count = recv((SOCKET)sock->realsocket,
(char *)(sock->inbuf + sock->reclen),
(sock->inbuflen - sock->reclen), 0);
}
else
{
/* we are calling this from PollGroup, so it cannot block */
fd_set fdset;
struct timeval t = {0,0};
FD_ZERO(&fdset);
FD_SET((SOCKET)sock->realsocket, &fdset);
if(select(sock->realsocket + 1, &fdset, NULL, NULL, &t) == 1)
{
count = recv((SOCKET)sock->realsocket,
(char *)(sock->inbuf + sock->reclen),
(sock->inbuflen - sock->reclen), 0);
}
else
{
/* socket would block, so break */
break;
}
}
if(count == SOCKET_ERROR)
{
if(checkonly == NL_FALSE)
{
/* check to see if we already have all the packet */
if(len <= (NLushort)(sock->reclen - c))
{
done = NL_TRUE;
}
else
{
/* report the error */
return sock_Error();
}
}
else
{
done = NL_TRUE;
}
}
else if(count == 0)
{
sock->message_end = NL_TRUE;
sock->readable = NL_TRUE;
done = NL_TRUE;
}
else
{
sock->reclen += count;
if(len <= (NLushort)(sock->reclen - c))
{
done = NL_TRUE;
}
}
}
}
/* see if we now have all of the packet */
if(len <= (NLushort)(sock->reclen - c))
{
sock->readable = NL_TRUE;
if(checkonly == NL_FALSE)
{
/* copy the packet */
memcpy(buffer, (sock->inbuf + c), (size_t)len);
/* check for another packet */
sock->reclen -= (len + c);
if(sock->reclen > 0)
{
/* move it down to the beginning of inbuf */
memmove(sock->inbuf, (sock->inbuf + c + len), (size_t)sock->reclen);
}
/* quick check to see if we have another complete packet buffered */
if(sock->reclen >= NL_HEADER_LEN)
{
NLushort templen;
/* read the length of the packet */
c = 2;
readShort(sock->inbuf, c, templen);
/* check the length */
if(templen <= (NLushort)(sock->reclen - c))
{
/* we have another complete packet, so mark as readable for PollGroup */
sock->readable = NL_TRUE;
}
else
{
sock->readable = NL_FALSE;
}
}
else
{
sock->readable = NL_FALSE;
}
return (NLint)len;
}
}
else
{
return 0;
}
}
return 0;
}
NLint sock_Read(NLsocket socket, NLvoid *buffer, NLint nbytes)
{
nl_socket_t *sock = nlSockets[socket];
NLint count;
if(nbytes < 0)
{
return 0;
}
if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) /* TCP */
{
/* check for a non-blocking connection pending */
if(sock->connecting == NL_TRUE)
{
fd_set fdset;
struct timeval t = {0,0};
int serrval = -1;
socklen_t serrsize = (socklen_t)sizeof(serrval);
FD_ZERO(&fdset);
FD_SET((SOCKET)sock->realsocket, &fdset);
if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
{
/* Check the socket status */
(void)getsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize );
if(serrval != 0)
{
if(serrval == (int)ECONNREFUSED)
{
nlSetError(NL_CON_REFUSED);
}
else if(serrval == (int)EINPROGRESS || serrval == (int)EWOULDBLOCK)
{
nlSetError(NL_CON_PENDING);
}
return NL_INVALID;
}
/* the connect has completed */
sock->connected = NL_TRUE;
sock->connecting = NL_FALSE;
}
else
{
/* check for a failed connect */
FD_ZERO(&fdset);
FD_SET((SOCKET)sock->realsocket, &fdset);
if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
{
nlSetError(NL_CON_REFUSED);
}
else
{
nlSetError(NL_CON_PENDING);
}
return NL_INVALID;
}
}
/* check for reliable packets */
if(sock->type == NL_RELIABLE_PACKETS)
{
return sock_ReadPacket(socket, buffer, nbytes, NL_FALSE);
}
count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
if(count == 0)
{
/* end of message */
nlSetError(NL_MESSAGE_END);
return NL_INVALID;
}
}
else /* UDP */
{
/* check for a non-blocking connection pending */
if(sock->connecting == NL_TRUE)
{
nlSetError(NL_CON_PENDING);
return NL_INVALID;
}
/* check for a connection error */
if(sock->conerror == NL_TRUE)
{
nlSetError(NL_CON_REFUSED);
return NL_INVALID;
}
if(sock->connected == NL_TRUE)
{
count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
}
else
{
socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
count = recvfrom((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
(struct sockaddr *)&sock->addressin, &len);
}
}
if(count == SOCKET_ERROR)
{
return sock_Error();
}
return count;
}
static NLboolean allocateBuffer(nl_socket_t *sock, NLint nbytes)
{
NLint size = NLMIN(NLMAX((nbytes + NL_HEADER_LEN) * 2, 1024), (NL_MAX_PACKET_LENGTH + NL_HEADER_LEN));
/* first call */
if(sock->outbuf == NULL)
{
sock->outbuf = (NLbyte *)malloc((size_t)size);
if(sock->outbuf == NULL)
{
sock->outbuflen = 0;
nlSetError(NL_OUT_OF_MEMORY);
return NL_FALSE;
}
sock->outbuflen = size;
}
else
{
if(size > sock->outbuflen)
{
NLbyte *temp;
temp = (NLbyte *)realloc(sock->outbuf, (size_t)size);
if(temp == NULL)
{
sock->outbuflen = 0;
nlSetError(NL_OUT_OF_MEMORY);
return NL_FALSE;
}
sock->outbuf = temp;
sock->outbuflen = size;
}
}
return NL_TRUE;
}
static NLint sock_WritePacket(NLsocket socket, const NLvoid *buffer, NLint nbytes)
{
nl_socket_t *sock = nlSockets[socket];
NLint count;
NLbyte temp[NL_HEADER_LEN];
NLint c = 0;
/* allocate memory for outbuf */
if(sock->outbuf == NULL)
{
if(allocateBuffer(sock, nbytes) == NL_FALSE)
{
return NL_INVALID;
}
}
else
{
/* send any unsent data from last packet */
sock_WritePacketCheckPending(socket);
}
/* check to see if we already have some pending data */
if(sock->sendlen > 0)
{
/* to comply with the way UDP packets act */
/* if the send buffer has unsent data return 0 */
return 0;
}
/* ID for packets is 'NL'*/
writeByte(temp, c, 'N');
writeByte(temp, c, 'L');
/* add the packet length */
writeShort(temp, c, (NLushort)nbytes);
count = send((SOCKET)sock->realsocket, (char *)temp, c, 0);
if(count == SOCKET_ERROR)
{
if(sockerrno == (int)EWOULDBLOCK)
{
count = 0;
}
else
{
return sock_Error();
}
}
if(count < c)
{
int dif = c - count;
/* check outbuf size */
if(allocateBuffer(sock, nbytes) == NL_FALSE)
{
return NL_INVALID;
}
/* store it */
memcpy((sock->outbuf + sock->sendlen), (temp + count), (size_t)(dif));
sock->sendlen += (dif);
memcpy((sock->outbuf + sock->sendlen), ((NLbyte *)buffer), (size_t)(nbytes));
sock->sendlen += (nbytes);
rpBufferedCount++;
}
else
{
count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
if(count == SOCKET_ERROR)
{
if(sockerrno == (int)EWOULDBLOCK)
{
count = 0;
}
else
{
return sock_Error();
}
}
/* make sure all was sent */
if(count < nbytes)
{
int dif = nbytes - count;
/* check outbuf size */
if(allocateBuffer(sock, nbytes) == NL_FALSE)
{
return NL_INVALID;
}
/* store it */
memcpy((sock->outbuf + sock->sendlen), ((NLbyte *)buffer + count), (size_t)(dif));
sock->sendlen += dif;
rpBufferedCount++;
}
}
count = nbytes;
return count;
}
NLint sock_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes)
{
nl_socket_t *sock = nlSockets[socket];
NLint count;
if(nbytes < 0)
{
return 0;
}
if((sock->type == NL_RELIABLE) || (sock->type == NL_RELIABLE_PACKETS)) /* TCP */
{
if(sock->connecting == NL_TRUE)
{
fd_set fdset;
struct timeval t = {0,0};
int serrval = -1;
socklen_t serrsize = (socklen_t)sizeof(serrval);
FD_ZERO(&fdset);
FD_SET((SOCKET)sock->realsocket, &fdset);
if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
{
/* Check the socket status */
(void)getsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize );
if(serrval != 0)
{
if(serrval == (int)ECONNREFUSED)
{
nlSetError(NL_CON_REFUSED);
}
else if(serrval == (int)EINPROGRESS || serrval == (int)EWOULDBLOCK)
{
nlSetError(NL_CON_PENDING);
}
return NL_INVALID;
}
/* the connect has completed */
sock->connected = NL_TRUE;
sock->connecting = NL_FALSE;
}
else
{
/* check for a failed connect */
FD_ZERO(&fdset);
FD_SET((SOCKET)sock->realsocket, &fdset);
if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
{
nlSetError(NL_CON_REFUSED);
}
else
{
nlSetError(NL_CON_PENDING);
}
return NL_INVALID;
}
}
/* check for reliable packets */
if(sock->type == NL_RELIABLE_PACKETS)
{
if(nbytes > NL_MAX_PACKET_LENGTH)
{
nlSetError(NL_PACKET_SIZE);
return NL_INVALID;
}
return sock_WritePacket(socket, buffer, nbytes);
}
count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
}
else /* unconnected UDP */
{
int maxpacket = NL_MAX_PACKET_LENGTH;
int sizesockaddr = (int)sizeof(struct sockaddr_in);
/* check for a non-blocking connection pending */
if(sock->connecting == NL_TRUE)
{
nlSetError(NL_CON_PENDING);
return NL_INVALID;
}
/* check for a connection error */
if(sock->conerror == NL_TRUE)
{
nlSetError(NL_CON_REFUSED);
return NL_INVALID;
}
#ifdef NL_INCLUDE_IPX
if(sock->driver == NL_IPX)
{
maxpacket = 1466;
sizesockaddr = (int)sizeof(struct sockaddr_ipx);
}
#endif
if(nbytes > maxpacket)
{
nlSetError(NL_PACKET_SIZE);
return NL_INVALID;
}
if(sock->type == NL_UDP_MULTICAST)
{
count = sendto((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
(struct sockaddr *)&sock->addressout,
(int)sizeof(struct sockaddr_in));
}
else if(sock->connected == NL_TRUE)
{
count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
}
else
{
count = sendto((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
(struct sockaddr *)&sock->addressout, sizesockaddr);
}
}
if(count == SOCKET_ERROR)
{
return sock_Error();
}
return count;
}
NLchar *sock_AddrToString(const NLaddress *address, NLchar *string)
{
NLulong addr;
NLushort port;
addr = ntohl(((struct sockaddr_in *)address)->sin_addr.s_addr);
port = ntohs(((struct sockaddr_in *)address)->sin_port);
if(port == 0)
{
_stprintf(string, TEXT("%lu.%lu.%lu.%lu"), (addr >> 24) & 0xff, (addr >> 16)
& 0xff, (addr >> 8) & 0xff, addr & 0xff);
}
else
{
_stprintf(string, TEXT("%lu.%lu.%lu.%lu:%u"), (addr >> 24) & 0xff, (addr >> 16)
& 0xff, (addr >> 8) & 0xff, addr & 0xff, port);
}
return string;
}
NLboolean sock_StringToAddr(const NLchar *string, NLaddress *address)
{
NLulong a1, a2, a3, a4;
NLulong ipaddress, port = 0;
int ret;
ret = _stscanf((const NLchar *)string, (const NLchar *)TEXT("%lu.%lu.%lu.%lu:%lu"), &a1, &a2, &a3, &a4, &port);
if(a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255 || port > 65535 || ret < 4)
{
/* bad address */
((struct sockaddr_in *)address)->sin_family = AF_INET;
((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_NONE;
((struct sockaddr_in *)address)->sin_port = 0;
nlSetError(NL_BAD_ADDR);
address->valid = NL_FALSE;
return NL_FALSE;
}
else
{
ipaddress = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
((struct sockaddr_in *)address)->sin_family = AF_INET;
((struct sockaddr_in *)address)->sin_addr.s_addr = htonl(ipaddress);
((struct sockaddr_in *)address)->sin_port = htons((NLushort)port);
address->valid = NL_TRUE;
return NL_TRUE;
}
}
NLboolean sock_GetLocalAddr(NLsocket socket, NLaddress *address)
{
nl_socket_t *sock = nlSockets[socket];
socklen_t len;
memset(address, 0, sizeof(NLaddress));
((struct sockaddr_in *)address)->sin_family = AF_INET;
address->valid = NL_TRUE;
len = (socklen_t)sizeof(struct sockaddr_in);
/* if the socket is connected, this will get us
the correct address on a multihomed system*/
if(getsockname((SOCKET)sock->realsocket, (struct sockaddr *)address, &len) == SOCKET_ERROR)
{
/* ignore error if socket has not been bound or connected yet */
if(sockerrno != (int)EINVAL)
{
nlSetError(NL_SYSTEM_ERROR);
address->valid = NL_FALSE;
return NL_FALSE;
}
}
/* if not connected, substitute the NIC address */
if(((struct sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY)
{
((struct sockaddr_in *)address)->sin_addr.s_addr = ouraddress;
}
sock_SetAddrPort(address, sock->localport);
return NL_TRUE;
}
NLaddress *sock_GetAllLocalAddr(NLint *count)
{
struct hostent *local;
char buff[MAXHOSTNAMELEN];
int i = 0;
if(gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
{
nlSetError(NL_SYSTEM_ERROR);
return NULL;
}
buff[MAXHOSTNAMELEN - 1] = '\0';
local = gethostbyname(buff);
if(local == NULL)
{
if(sockerrno == (int)ENETDOWN)
{
nlSetError(NL_SYSTEM_ERROR);
return NULL;
}
}
/* count the number of returned IP addresses */
*count = 0;
if(local != NULL)
{
while(local->h_addr_list[i++] != NULL)
{
(*count)++;
}
}
/* allocate storage for address */
if(alladdr != NULL)
{
free(alladdr);
}
if(*count == 0)
{
*count = 1;
alladdr = (NLaddress *)malloc(sizeof(NLaddress));
memset(alladdr, 0, sizeof(NLaddress));
/* fill in the localhost address */
((struct sockaddr_in *)alladdr)->sin_family = AF_INET;
((struct sockaddr_in *)alladdr)->sin_addr.s_addr = (NLuint)htonl(0x7f000001);
alladdr->valid = NL_TRUE;
}
else
{
alladdr = (NLaddress *)malloc(sizeof(NLaddress) * *count);
memset(alladdr, 0, sizeof(NLaddress) * *count);
/* fill in the addresses */
i = 0;
while(local->h_addr_list[i] != NULL)
{
NLaddress *addr = &alladdr[i];
((struct sockaddr_in *)addr)->sin_family = AF_INET;
((struct sockaddr_in *)addr)->sin_addr.s_addr = *(NLuint *)local->h_addr_list[i];
addr->valid = NL_TRUE;
i++;
}
}
return alladdr;
}
NLboolean sock_SetLocalAddr(const NLaddress *address)
{
/* should we check against all the local addresses? */
bindaddress = ouraddress = (NLuint)((struct sockaddr_in *)address)->sin_addr.s_addr;
return NL_TRUE;
}
NLchar *sock_GetNameFromAddr(const NLaddress *address, NLchar *name)
{
struct hostent *hostentry;
NLchar tempname[MAXHOSTNAMELEN];
hostentry = gethostbyaddr((char *)&((struct sockaddr_in *)address)->sin_addr,
(int)sizeof(struct in_addr), AF_INET);
if(hostentry != NULL)
{
NLushort port = sock_GetPortFromAddr(address);
#ifdef _UNICODE
NLchar temp[MAXHOSTNAMELEN];
/* convert from multibyte char string to wide char string */
mbstowcs(temp, (const char *)hostentry->h_name, MAXHOSTNAMELEN);
temp[MAXHOSTNAMELEN - 1] = '\0';
#else
NLchar *temp = (NLchar *)hostentry->h_name;
#endif
if(port != 0)
{
_sntprintf(tempname, (size_t)(NL_MAX_STRING_LENGTH), (const NLchar *)TEXT("%s:%hu"), (const NLchar *)temp, port);
}
else
{
_tcsncpy(tempname, (const NLchar *)temp, (size_t)(NL_MAX_STRING_LENGTH));
}
tempname[NL_MAX_STRING_LENGTH - 1] = (NLchar)'\0';
}
else
{
if(((struct sockaddr_in *)address)->sin_addr.s_addr == (unsigned long)INADDR_NONE)
{
_tcsncpy(tempname, (const NLchar *)TEXT("Bad address"), (size_t)(NL_MAX_STRING_LENGTH));
}
else
{
(void)sock_AddrToString(address, tempname);
}
}
/* special copy in case this was called as sock_GetNameFromAddrAsync */
name[0] = (NLchar)'\0';
_tcsncpy(&name[1], (const NLchar *)&tempname[1], (size_t)(NL_MAX_STRING_LENGTH - 1));
name[0] = tempname[0];
return name;
}
static void *sock_GetNameFromAddrAsyncInt(void /*@owned@*/ * addr)
{
NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
(void)sock_GetNameFromAddr(address->address, address->name);
free(address->address);
free(address);
return NULL;
}
NLboolean sock_GetNameFromAddrAsync(const NLaddress *address, NLchar *name)
{
NLaddress_ex_t *addr;
memset(name, 0, sizeof(NLchar) * NL_MAX_STRING_LENGTH);
addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
if(addr == NULL)
{
nlSetError(NL_OUT_OF_MEMORY);
return NL_FALSE;
}
addr->address = (NLaddress *)malloc(sizeof(NLaddress));
if(addr->address == NULL)
{
nlSetError(NL_OUT_OF_MEMORY);
free(addr);
return NL_FALSE;
}
memcpy(addr->address, address, sizeof(NLaddress));
addr->name = name;
Util::Thread::Id thread;
if (!Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) sock_GetNameFromAddrAsyncInt, (void *)addr)){
return NL_FALSE;
}
return NL_TRUE;
}
NLboolean sock_GetAddrFromName(const NLchar *name, NLaddress *address)
{
struct hostent *hostentry;
NLushort port = 0;
int pos;
NLbyte temp[NL_MAX_STRING_LENGTH];
address->valid = NL_FALSE;
/* first check to see if we have a numeric address already */
(void)sock_StringToAddr(name, address);
/* clear out an NL_BAD_ADDR error */
if(nlGetError() == NL_BAD_ADDR)
{
nlSetError(NL_NO_ERROR);
}
if(((struct sockaddr_in *)address)->sin_addr.s_addr != (unsigned long)INADDR_NONE)
{
/* we are already done! */
address->valid = NL_TRUE;
return NL_TRUE;
}
#ifdef _UNICODE
/* convert from wide char string to multibyte char string */
(void)wcstombs(temp, (const NLchar *)name, NL_MAX_STRING_LENGTH);
#else
strncpy(temp, name, NL_MAX_STRING_LENGTH);
#endif
temp[NL_MAX_STRING_LENGTH - 1] = (NLbyte)'\0';
pos = (int)strcspn(temp, (const char *)":");
if(pos > 0)
{
NLbyte *p = &temp[pos+1];
temp[pos] = (NLbyte)'\0';
(void)sscanf(p, "%hu", &port);
}
hostentry = gethostbyname((const char *)temp);
if(hostentry != NULL)
{
((struct sockaddr_in *)address)->sin_family = AF_INET;
((struct sockaddr_in *)address)->sin_port = htons(port);
((struct sockaddr_in *)address)->sin_addr.s_addr = *(NLulong *)hostentry->h_addr_list[0];
address->valid = NL_TRUE;
}
else
{
((struct sockaddr_in *)address)->sin_family = AF_INET;
((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_NONE;
((struct sockaddr_in *)address)->sin_port = 0;
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
return NL_TRUE;
}
static void *sock_GetAddrFromNameAsyncInt(void /*@owned@*/ *addr)
{
NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
(void)sock_GetAddrFromName(address->name, address->address);
address->address->valid = NL_TRUE;
free(address->name);
free(address);
return NULL;
}
NLboolean sock_GetAddrFromNameAsync(const NLchar *name, NLaddress *address)
{
NLaddress_ex_t *addr;
address->valid = NL_FALSE;
addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
if(addr == NULL)
{
nlSetError(NL_OUT_OF_MEMORY);
return NL_FALSE;
}
addr->name = (NLchar *)malloc(NL_MAX_STRING_LENGTH);
if(addr->name == NULL)
{
nlSetError(NL_OUT_OF_MEMORY);
free(addr);
return NL_FALSE;
}
_tcsncpy(addr->name, name, (size_t)NL_MAX_STRING_LENGTH);
addr->name[NL_MAX_STRING_LENGTH - 1] = '\0';
addr->address = address;
Util::Thread::Id thread;
if (!Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) sock_GetAddrFromNameAsyncInt, (void *)addr)){
return NL_FALSE;
}
return NL_TRUE;
}
NLboolean sock_AddrCompare(const NLaddress *address1, const NLaddress *address2)
{
if(((struct sockaddr_in *)address1)->sin_family != ((struct sockaddr_in *)address2)->sin_family)
return NL_FALSE;
if(((struct sockaddr_in *)address1)->sin_addr.s_addr
!= ((struct sockaddr_in *)address2)->sin_addr.s_addr)
return NL_FALSE;
if(((struct sockaddr_in *)address1)->sin_port
!= ((struct sockaddr_in *)address2)->sin_port)
return NL_FALSE;
return NL_TRUE;
}
NLushort sock_GetPortFromAddr(const NLaddress *address)
{
return ntohs(((struct sockaddr_in *)address)->sin_port);
}
void sock_SetAddrPort(NLaddress *address, NLushort port)
{
((struct sockaddr_in *)address)->sin_port = htons((NLushort)port);
}
NLint sock_GetSystemError(void)
{
NLint err = sockerrno;
#ifdef HL_WINDOWS_APP
if(err < WSABASEERR)
{
if(errno > 0)
{
err = errno;
}
}
#endif
return err;
}
NLint sock_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout)
{
NLint numselect, count = 0;
NLint numsockets = NL_MAX_GROUP_SOCKETS;
NLsocket temp[NL_MAX_GROUP_SOCKETS];
NLboolean reliable[NL_MAX_GROUP_SOCKETS];
NLboolean result;
NLsocket *ptemp = temp;
int i, found = 0;
fd_set fdset;
SOCKET highest;
struct timeval t = {0,0}; /* {seconds, useconds}*/
struct timeval *tp = &t;
nlGroupLock();
highest = nlGroupGetFdset(group, &fdset);
if(highest == INVALID_SOCKET)
{
/* error is set by nlGroupGetFdset */
nlGroupUnlock();
return NL_INVALID;
}
result = nlGroupGetSocketsINT(group, ptemp, &numsockets);
nlGroupUnlock();
if(result == NL_FALSE)
{
/* any error is set by nlGroupGetSockets */
return NL_INVALID;
}
if(numsockets == 0)
{
return 0;
}
if(name == NL_READ_STATUS)
{
/* check for buffered reliable packets */
for(i=0;i<numsockets;i++)
{
nl_socket_t *s = nlSockets[ptemp[i]];
if(s->type == NL_RELIABLE_PACKETS && s->readable == NL_TRUE)
{
/* mark as readable */
reliable[i] = NL_TRUE;
found++;
/* change the timeout to 0, or non-blocking since we */
/* have at least one reliable packet to read */
timeout = 0;
}
else
{
reliable[i] = NL_FALSE;
}
}
}
/* check for full blocking call */
if(timeout < 0)
{
tp = NULL;
}
else /* set t values */
{
t.tv_sec = timeout/1000;
t.tv_usec = (timeout%1000) * 1000;
}
/* call select to check the status */
switch(name) {
case NL_READ_STATUS:
numselect = select((int)highest, &fdset, NULL, NULL, tp);
break;
case NL_WRITE_STATUS:
numselect = select((int)highest, NULL, &fdset, NULL, tp);
break;
case NL_ERROR_STATUS:
numselect = select((int)highest, NULL, NULL, &fdset, tp);
break;
default:
nlSetError(NL_INVALID_ENUM);
return NL_INVALID;
}
if(numselect == SOCKET_ERROR)
{
if(sockerrno == (int)ENOTSOCK)
{
/* one of the sockets has been closed */
nlSetError(NL_INVALID_SOCKET);
}
else if(sockerrno == (int)EINTR)
{
/* select was interrupted by the system, maybe because the app is exiting */
return 0;
}
else
{
nlSetError(NL_SYSTEM_ERROR);
}
return NL_INVALID;
}
if(numselect > number)
{
nlSetError(NL_BUFFER_SIZE);
return NL_INVALID;
}
/* fill *sockets with a list of the sockets ready to be read */
numselect += found;
i = 0;
while(numsockets-- > 0 && numselect > count)
{
nl_socket_t *s = nlSockets[*ptemp];
if((reliable[i] == NL_TRUE ) || (FD_ISSET(s->realsocket, &fdset) != 0))
{
/* if checking for read status, must check for a complete packet */
if(s->type == NL_RELIABLE_PACKETS && s->listen == NL_FALSE && name == NL_READ_STATUS)
{
(void)nlLockSocket(*ptemp, NL_READ);
if(s->readable != NL_TRUE)
{
if(s->inuse == NL_TRUE)
{
(void)sock_ReadPacket(*ptemp, NULL, 0, NL_TRUE);
}
else
{
s->readable = NL_FALSE;
}
}
if(s->readable == NL_TRUE)
{
/* we do have a complete packet */
*sockets = *ptemp;
sockets++;
count++;
}
nlUnlockSocket(*ptemp, NL_READ);
}
else
{
*sockets = *ptemp;
sockets++;
count ++;
}
}
i++;
ptemp++;
}
return count;
}
NLboolean sock_PollSocket(NLsocket socket, NLenum name, NLint timeout)
{
NLint numselect;
nl_socket_t *sock = nlSockets[socket];
fd_set fdset;
struct timeval t = {0,0}; /* {seconds, useconds}*/
struct timeval *tp = &t;
nlSetError(NL_NO_ERROR);
if(name == NL_READ_STATUS)
{
/* check for buffered reliable packets */
nl_socket_t *s = nlSockets[socket];
if(s->type == NL_TCP_PACKETS && s->readable == NL_TRUE)
{
return NL_TRUE;
}
}
/* check for full blocking call */
if(timeout < 0)
{
tp = NULL;
}
else /* set t values */
{
t.tv_sec = timeout/1000;
t.tv_usec = (timeout%1000) * 1000;
}
FD_ZERO(&fdset);
FD_SET((SOCKET)(sock->realsocket), &fdset);
/* call select to check the status */
switch(name) {
case NL_READ_STATUS:
numselect = select((int)(sock->realsocket + 1), &fdset, NULL, NULL, tp);
break;
case NL_WRITE_STATUS:
numselect = select((int)(sock->realsocket + 1), NULL, &fdset, NULL, tp);
break;
case NL_ERROR_STATUS:
numselect = select((int)(sock->realsocket + 1), NULL, NULL, &fdset, tp);
break;
default:
nlSetError(NL_INVALID_ENUM);
return NL_FALSE;
}
if(numselect == SOCKET_ERROR)
{
if(sockerrno == (int)ENOTSOCK)
{
/* the socket has been closed */
nlSetError(NL_INVALID_SOCKET);
}
else if(sockerrno == (int)EINTR)
{
/* select was interrupted by the system, maybe because the app is exiting */
return NL_FALSE;
}
else
{
nlSetError(NL_SYSTEM_ERROR);
}
}
else if(numselect == 1)
{
return NL_TRUE;
}
return NL_FALSE;
}
NLboolean sock_Hint(NLenum name, NLint arg)
{
switch(name) {
case NL_LISTEN_BACKLOG:
backlog = arg;
break;
case NL_MULTICAST_TTL:
if(arg < 1)
{
arg = 1;
}
else if(arg > 255)
{
arg = 255;
}
multicastTTL = arg;
break;
case NL_REUSE_ADDRESS:
reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
break;
case NL_TCP_NO_DELAY:
nlTCPNoDelay = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
break;
default:
nlSetError(NL_INVALID_ENUM);
return NL_FALSE;
}
return NL_TRUE;
}
NLboolean sock_SetSocketOpt(NLsocket socket, NLenum name, NLint arg)
{
nl_socket_t *sock = nlSockets[socket];
switch (name) {
case NL_BLOCKING_IO:
sock->blocking = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
if(sock_SetBlocking((SOCKET)sock->realsocket, sock->blocking) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
break;
case NL_MULTICAST_TTL:
if(sock->type == NL_UDP_MULTICAST)
{
return(sock_SetMulticastTTL(sock, multicastTTL));
}
else
{
nlSetError(NL_INVALID_ENUM);
return NL_FALSE;
}
case NL_REUSE_ADDRESS:
if(sock_SetReuseAddr(sock) == NL_FALSE)
{
nlSetError(NL_SYSTEM_ERROR);
return NL_FALSE;
}
break;
case NL_TCP_NO_DELAY:
return (sock_SetTCPNoDelay(sock, (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE)));
default:
nlSetError(NL_INVALID_ENUM);
return NL_FALSE;
}
return NL_TRUE;
}
NLint sock_GetSocketOpt(NLsocket socket, NLenum name)
{
nl_socket_t *sock = nlSockets[socket];
switch (name) {
case NL_BLOCKING_IO:
return (NLint)sock->blocking;
case NL_MULTICAST_TTL:
if(sock->type == NL_UDP_MULTICAST)
{
return sock->TTL;
}
else
{
nlSetError(NL_INVALID_ENUM);
return NL_FALSE;
}
case NL_REUSE_ADDRESS:
return (NLint)sock->reuseaddr;
case NL_TCP_NO_DELAY:
return (NLint)sock->TCPNoDelay;
default:
nlSetError(NL_INVALID_ENUM);
return NL_INVALID;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 18, 8:49 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71689
Default Alt Text
(82 KB)

Event Timeline