The codeblocks editor cleans up surplus whitespace with every save by default. That's nice, as long as everyone uses it. Otherwise, changes in whitespace will creep into most commits and make the diffs hard to read. Therefore: one commit with _only_ whitespace changed.
476 lines
10 KiB
C
476 lines
10 KiB
C
/**
|
|
@file unix.c
|
|
@brief ENet Unix system specific functions
|
|
*/
|
|
#ifndef WIN32
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
#define ENET_BUILDING_LIB 1
|
|
#include "enet/enet.h"
|
|
|
|
#ifdef __APPLE__
|
|
#ifdef HAS_POLL
|
|
#undef HAS_POLL
|
|
#endif
|
|
#ifndef HAS_FCNTL
|
|
#define HAS_FCNTL 1
|
|
#endif
|
|
#ifndef HAS_INET_PTON
|
|
#define HAS_INET_PTON 1
|
|
#endif
|
|
#ifndef HAS_INET_NTOP
|
|
#define HAS_INET_NTOP 1
|
|
#endif
|
|
#ifndef HAS_MSGHDR_FLAGS
|
|
#define HAS_MSGHDR_FLAGS 1
|
|
#endif
|
|
#ifndef HAS_SOCKLEN_T
|
|
#define HAS_SOCKLEN_T 1
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef HAS_FCNTL
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAS_POLL
|
|
#include <sys/poll.h>
|
|
#endif
|
|
|
|
#ifndef HAS_SOCKLEN_T
|
|
typedef int socklen_t;
|
|
#endif
|
|
|
|
#ifndef MSG_NOSIGNAL
|
|
#define MSG_NOSIGNAL 0
|
|
#endif
|
|
|
|
static enet_uint32 timeBase = 0;
|
|
|
|
int
|
|
enet_initialize (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
enet_deinitialize (void)
|
|
{
|
|
}
|
|
|
|
enet_uint32
|
|
enet_time_get (void)
|
|
{
|
|
struct timeval timeVal;
|
|
|
|
gettimeofday (& timeVal, NULL);
|
|
|
|
return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase;
|
|
}
|
|
|
|
void
|
|
enet_time_set (enet_uint32 newTimeBase)
|
|
{
|
|
struct timeval timeVal;
|
|
|
|
gettimeofday (& timeVal, NULL);
|
|
|
|
timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase;
|
|
}
|
|
|
|
int
|
|
enet_address_set_host (ENetAddress * address, const char * name)
|
|
{
|
|
struct hostent * hostEntry = NULL;
|
|
#ifdef HAS_GETHOSTBYNAME_R
|
|
struct hostent hostData;
|
|
char buffer [2048];
|
|
int errnum;
|
|
|
|
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
|
|
#else
|
|
hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum);
|
|
#endif
|
|
#else
|
|
hostEntry = gethostbyname (name);
|
|
#endif
|
|
|
|
if (hostEntry == NULL ||
|
|
hostEntry -> h_addrtype != AF_INET)
|
|
{
|
|
#ifdef HAS_INET_PTON
|
|
if (! inet_pton (AF_INET, name, & address -> host))
|
|
#else
|
|
if (! inet_aton (name, (struct in_addr *) & address -> host))
|
|
#endif
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
|
|
{
|
|
#ifdef HAS_INET_NTOP
|
|
if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL)
|
|
#else
|
|
char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
|
|
if (addr != NULL)
|
|
strncpy (name, addr, nameLength);
|
|
else
|
|
#endif
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
|
|
{
|
|
struct in_addr in;
|
|
struct hostent * hostEntry = NULL;
|
|
#ifdef HAS_GETHOSTBYADDR_R
|
|
struct hostent hostData;
|
|
char buffer [2048];
|
|
int errnum;
|
|
|
|
in.s_addr = address -> host;
|
|
|
|
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
|
|
#else
|
|
hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum);
|
|
#endif
|
|
#else
|
|
in.s_addr = address -> host;
|
|
|
|
hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
|
|
#endif
|
|
|
|
if (hostEntry == NULL)
|
|
return enet_address_get_host_ip (address, name, nameLength);
|
|
|
|
strncpy (name, hostEntry -> h_name, nameLength);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
enet_socket_bind (ENetSocket socket, const ENetAddress * address)
|
|
{
|
|
struct sockaddr_in sin;
|
|
|
|
memset (& sin, 0, sizeof (struct sockaddr_in));
|
|
|
|
sin.sin_family = AF_INET;
|
|
|
|
if (address != NULL)
|
|
{
|
|
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
|
|
sin.sin_addr.s_addr = address -> host;
|
|
}
|
|
else
|
|
{
|
|
sin.sin_port = 0;
|
|
sin.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
return bind (socket,
|
|
(struct sockaddr *) & sin,
|
|
sizeof (struct sockaddr_in));
|
|
}
|
|
|
|
int
|
|
enet_socket_listen (ENetSocket socket, int backlog)
|
|
{
|
|
return listen (socket, backlog < 0 ? SOMAXCONN : backlog);
|
|
}
|
|
|
|
ENetSocket
|
|
enet_socket_create (ENetSocketType type)
|
|
{
|
|
return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
|
|
}
|
|
|
|
int
|
|
enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
|
|
{
|
|
int result = -1;
|
|
switch (option)
|
|
{
|
|
case ENET_SOCKOPT_NONBLOCK:
|
|
#ifdef HAS_FCNTL
|
|
result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL));
|
|
#else
|
|
result = ioctl (socket, FIONBIO, & value);
|
|
#endif
|
|
break;
|
|
|
|
case ENET_SOCKOPT_BROADCAST:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
case ENET_SOCKOPT_REUSEADDR:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
case ENET_SOCKOPT_RCVBUF:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
case ENET_SOCKOPT_SNDBUF:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
case ENET_SOCKOPT_RCVTIMEO:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
case ENET_SOCKOPT_SNDTIMEO:
|
|
result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return result == -1 ? -1 : 0;
|
|
}
|
|
|
|
int
|
|
enet_socket_connect (ENetSocket socket, const ENetAddress * address)
|
|
{
|
|
struct sockaddr_in sin;
|
|
int result;
|
|
|
|
memset (& sin, 0, sizeof (struct sockaddr_in));
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
|
|
sin.sin_addr.s_addr = address -> host;
|
|
|
|
result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
|
|
if (result == -1 && errno == EINPROGRESS)
|
|
return 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
ENetSocket
|
|
enet_socket_accept (ENetSocket socket, ENetAddress * address)
|
|
{
|
|
int result;
|
|
struct sockaddr_in sin;
|
|
socklen_t sinLength = sizeof (struct sockaddr_in);
|
|
|
|
result = accept (socket,
|
|
address != NULL ? (struct sockaddr *) & sin : NULL,
|
|
address != NULL ? & sinLength : NULL);
|
|
|
|
if (result == -1)
|
|
return ENET_SOCKET_NULL;
|
|
|
|
if (address != NULL)
|
|
{
|
|
address -> host = (enet_uint32) sin.sin_addr.s_addr;
|
|
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int
|
|
enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how)
|
|
{
|
|
return shutdown (socket, (int) how);
|
|
}
|
|
|
|
void
|
|
enet_socket_destroy (ENetSocket socket)
|
|
{
|
|
if (socket != -1)
|
|
close (socket);
|
|
}
|
|
|
|
int
|
|
enet_socket_send (ENetSocket socket,
|
|
const ENetAddress * address,
|
|
const ENetBuffer * buffers,
|
|
size_t bufferCount)
|
|
{
|
|
struct msghdr msgHdr;
|
|
struct sockaddr_in sin;
|
|
int sentLength;
|
|
|
|
memset (& msgHdr, 0, sizeof (struct msghdr));
|
|
|
|
if (address != NULL)
|
|
{
|
|
memset (& sin, 0, sizeof (struct sockaddr_in));
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
|
|
sin.sin_addr.s_addr = address -> host;
|
|
|
|
msgHdr.msg_name = & sin;
|
|
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
|
|
}
|
|
|
|
msgHdr.msg_iov = (struct iovec *) buffers;
|
|
msgHdr.msg_iovlen = bufferCount;
|
|
|
|
sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL);
|
|
|
|
if (sentLength == -1)
|
|
{
|
|
if (errno == EWOULDBLOCK)
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
return sentLength;
|
|
}
|
|
|
|
int
|
|
enet_socket_receive (ENetSocket socket,
|
|
ENetAddress * address,
|
|
ENetBuffer * buffers,
|
|
size_t bufferCount)
|
|
{
|
|
struct msghdr msgHdr;
|
|
struct sockaddr_in sin;
|
|
int recvLength;
|
|
|
|
memset (& msgHdr, 0, sizeof (struct msghdr));
|
|
|
|
if (address != NULL)
|
|
{
|
|
msgHdr.msg_name = & sin;
|
|
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
|
|
}
|
|
|
|
msgHdr.msg_iov = (struct iovec *) buffers;
|
|
msgHdr.msg_iovlen = bufferCount;
|
|
|
|
recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL);
|
|
|
|
if (recvLength == -1)
|
|
{
|
|
if (errno == EWOULDBLOCK)
|
|
return 0;
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef HAS_MSGHDR_FLAGS
|
|
if (msgHdr.msg_flags & MSG_TRUNC)
|
|
return -1;
|
|
#endif
|
|
|
|
if (address != NULL)
|
|
{
|
|
address -> host = (enet_uint32) sin.sin_addr.s_addr;
|
|
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
|
|
}
|
|
|
|
return recvLength;
|
|
}
|
|
|
|
int
|
|
enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout)
|
|
{
|
|
struct timeval timeVal;
|
|
|
|
timeVal.tv_sec = timeout / 1000;
|
|
timeVal.tv_usec = (timeout % 1000) * 1000;
|
|
|
|
return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal);
|
|
}
|
|
|
|
int
|
|
enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout)
|
|
{
|
|
#ifdef HAS_POLL
|
|
struct pollfd pollSocket;
|
|
int pollCount;
|
|
|
|
pollSocket.fd = socket;
|
|
pollSocket.events = 0;
|
|
|
|
if (* condition & ENET_SOCKET_WAIT_SEND)
|
|
pollSocket.events |= POLLOUT;
|
|
|
|
if (* condition & ENET_SOCKET_WAIT_RECEIVE)
|
|
pollSocket.events |= POLLIN;
|
|
|
|
pollCount = poll (& pollSocket, 1, timeout);
|
|
|
|
if (pollCount < 0)
|
|
return -1;
|
|
|
|
* condition = ENET_SOCKET_WAIT_NONE;
|
|
|
|
if (pollCount == 0)
|
|
return 0;
|
|
|
|
if (pollSocket.revents & POLLOUT)
|
|
* condition |= ENET_SOCKET_WAIT_SEND;
|
|
|
|
if (pollSocket.revents & POLLIN)
|
|
* condition |= ENET_SOCKET_WAIT_RECEIVE;
|
|
|
|
return 0;
|
|
#else
|
|
fd_set readSet, writeSet;
|
|
struct timeval timeVal;
|
|
int selectCount;
|
|
|
|
timeVal.tv_sec = timeout / 1000;
|
|
timeVal.tv_usec = (timeout % 1000) * 1000;
|
|
|
|
FD_ZERO (& readSet);
|
|
FD_ZERO (& writeSet);
|
|
|
|
if (* condition & ENET_SOCKET_WAIT_SEND)
|
|
FD_SET (socket, & writeSet);
|
|
|
|
if (* condition & ENET_SOCKET_WAIT_RECEIVE)
|
|
FD_SET (socket, & readSet);
|
|
|
|
selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
|
|
|
|
if (selectCount < 0)
|
|
return -1;
|
|
|
|
* condition = ENET_SOCKET_WAIT_NONE;
|
|
|
|
if (selectCount == 0)
|
|
return 0;
|
|
|
|
if (FD_ISSET (socket, & writeSet))
|
|
* condition |= ENET_SOCKET_WAIT_SEND;
|
|
|
|
if (FD_ISSET (socket, & readSet))
|
|
* condition |= ENET_SOCKET_WAIT_RECEIVE;
|
|
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|